﻿// Copyright (c) Inossem. All rights reserved.
// Licensed under the LGPL-3.0 license. See LICENSE file in the project root for full license information.
using DWF.Studio.RemoteCtrls.ActivityToolBox;
using DWF.Studio.Share.Log;
using System;
using System.Activities;
using System.Activities.Presentation.Toolbox;
using System.Activities.Statements;
using System.AddIn.Contract;
using System.AddIn.Pipeline;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;

namespace DWF.Studio.RemoteCtrls.Proxy
{
    /// <summary>
    /// 活动工具栏代理
    /// </summary>
    public class ActivityToolBoxProxy : MarshalByRefProxyBase
    {
        /// <summary>
        /// 活动加载信息
        /// </summary>
        public Action<LoadInfoEventArgs> ActivityLoading = null;
        UCtrlActivityToolBox wfToolbox = null;
        /// <summary>
        /// 获取工具栏
        /// </summary>
        /// <param name="customActivityNames">自定义活动</param>
        /// <returns></returns>
        public INativeHandleContract GetToolBox1(string[] customActivityNames)
        {
            ToolboxControl wfToolbox = new ToolboxControl();

            var resource = new ResourceDictionary
            {
                Source = new Uri("/DWF.Studio.RemoteCtrls;component/Themes/ToolBoxStyle.xaml", UriKind.RelativeOrAbsolute)
            };

            var categoryItemstyle = ((Style)resource["CategoryItemStyle"]);
            var toolItemtyle = ((Style)resource["ToolItemStyle"]);

            wfToolbox.CategoryItemStyle = categoryItemstyle;
            wfToolbox.ToolItemStyle = toolItemtyle;

            AppDomain.CurrentDomain.Load("System.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
            AppDomain.CurrentDomain.Load("System.Activities.Core.Presentation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
            AppDomain.CurrentDomain.Load("Microsoft.Activities.Extensions, Version=2.0.6.9, Culture=neutral, PublicKeyToken=23b0c89d0d5ad43f");


            #region 自定义活动库 加载
            var customActivities = new List<Tuple<int, string, Assembly>>();
            foreach (string activity in customActivityNames)
            {
                try
                {
                    var assembly = AppDomain.CurrentDomain.Load(activity);

                    var resourceNames = assembly.GetManifestResourceNames();
                    var assemblyName = assembly.GetName();
                    var resourceName = assemblyName.Name + ".Resources.viewlangdic";

                    int sortNum = int.MaxValue;
                    string displayName = assemblyName.Name;

                    var isExisting = resourceNames.Any(item => item.Contains(resourceName));

                    if (isExisting)
                    {
                        var resourceManager = new ResourceManager(resourceName, assembly);

                        var DISPLAY_NO_string_value = resourceManager.GetString("DISPLAY_NO", System.Threading.Thread.CurrentThread.CurrentCulture);
                        int DISPLAY_NO_int_value;
                        var isok = Int32.TryParse(DISPLAY_NO_string_value, out DISPLAY_NO_int_value);
                        if (isok)
                        {
                            sortNum = DISPLAY_NO_int_value;
                        }

                        var GROUP_NAME_string_value = resourceManager.GetString("GROUP_NAME", System.Threading.Thread.CurrentThread.CurrentCulture);
                        if (!String.IsNullOrWhiteSpace(GROUP_NAME_string_value))
                        {
                            displayName = GROUP_NAME_string_value;
                        }
                    }

                    customActivities.Add(new Tuple<int, string, Assembly>(sortNum, displayName, assembly));
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }

            foreach (var activityLibrary in customActivities.OrderBy(item => item.Item1))
            {
                try
                {
                    var wfToolboxCategoryCustum = new ToolboxCategory(activityLibrary.Item2);
                    var actvities = from
                                        activityType in activityLibrary.Item3.GetExportedTypes()
                                    where
                                        (activityType.IsSubclassOf(typeof(Activity))
                                        || activityType.IsSubclassOf(typeof(NativeActivity))
                                        || activityType.IsSubclassOf(typeof(DynamicActivity))
                                        || activityType.IsSubclassOf(typeof(ActivityWithResult))
                                        || activityType.IsSubclassOf(typeof(AsyncCodeActivity))
                                        || activityType.IsSubclassOf(typeof(CodeActivity))
                                        || typeof(System.Activities.Presentation.IActivityTemplateFactory).IsAssignableFrom(activityType)
                                        || typeof(System.Activities.Presentation.IActivityTemplateFactory<FlowNode>).IsAssignableFrom(activityType)
                                        || activityType == typeof(System.Activities.Core.Presentation.Factories.ForEachWithBodyFactory<Type>)
                                        || activityType == typeof(System.Activities.Statements.TryCatch)
                                        || activityType == typeof(System.Activities.Statements.While))
                                        && activityType.IsVisible
                                        && activityType.IsPublic
                                        && !activityType.IsNested
                                        && !activityType.IsAbstract
                                        && (activityType.GetConstructor(Type.EmptyTypes) != null)
                                        && checkBrowsable(activityType)

                                    orderby
                                        activityType.Name
                                    select
                                        new ToolboxItemWrapper(activityType, getFriendlyTypeName(activityType));

                    foreach (var itemWrapper in actvities)
                    {
                        wfToolboxCategoryCustum.Add(itemWrapper);

                        if (ActivityLoading != null)
                        {
                            ActivityLoading(new LoadInfoEventArgs(itemWrapper.DisplayName));
                        }
                    }

                    if (wfToolboxCategoryCustum.Tools.Count > 0)
                    {
                        wfToolbox.Categories.Add(wfToolboxCategoryCustum);
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }

            #endregion

            return FrameworkElementAdapters.ViewToContractAdapter(wfToolbox);
        }

        public INativeHandleContract GetToolBox(string[] activityAssemblies)
        {
            wfToolbox = new UCtrlActivityToolBox();
            ActivityDesignerProxy.ModelChanged = wfToolbox.DesignerModelChanged;

            AppDomain.CurrentDomain.Load("System.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
            AppDomain.CurrentDomain.Load("System.Activities.Core.Presentation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
            AppDomain.CurrentDomain.Load("Microsoft.Activities.Extensions, Version=2.0.6.9, Culture=neutral, PublicKeyToken=23b0c89d0d5ad43f");
            AppDomain.CurrentDomain.Load("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
            AppDomain.CurrentDomain.Load("System.Data.DataSetExtensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");

            List<Type> activityTypes = new List<Type>();
            foreach (string activityAssembly in activityAssemblies)
            {
                try
                {
                    var assembly = Assembly.LoadFrom(activityAssembly);
                    var actvities = from
                                        activityType in assembly.GetExportedTypes()
                                    where
                                        (activityType.IsSubclassOf(typeof(Activity))
                                        || activityType.IsSubclassOf(typeof(NativeActivity))
                                        || activityType.IsSubclassOf(typeof(DynamicActivity))
                                        || activityType.IsSubclassOf(typeof(ActivityWithResult))
                                        || activityType.IsSubclassOf(typeof(AsyncCodeActivity))
                                        || activityType.IsSubclassOf(typeof(CodeActivity))
                                        || typeof(System.Activities.Presentation.IActivityTemplateFactory).IsAssignableFrom(activityType)
                                        || typeof(System.Activities.Presentation.IActivityTemplateFactory<FlowNode>).IsAssignableFrom(activityType)
                                        || activityType == typeof(System.Activities.Core.Presentation.Factories.ForEachWithBodyFactory<Type>)
                                        || activityType == typeof(System.Activities.Statements.TryCatch)
                                        || activityType == typeof(System.Activities.Statements.While))
                                        && activityType.IsVisible
                                        && activityType.IsPublic
                                        && !activityType.IsNested
                                        && !activityType.IsAbstract
                                        && (activityType.GetConstructor(Type.EmptyTypes) != null)
                                        && checkBrowsable(activityType)

                                    orderby
                                        activityType.Name
                                    select
                                        activityType;

                    activityTypes.AddRange(actvities);
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }

            wfToolbox.LoadActivies(activityTypes, (e) => { ActivityLoading?.Invoke(new LoadInfoEventArgs(e)); });

            return FrameworkElementAdapters.ViewToContractAdapter(wfToolbox);
        }
        /// <summary>
        /// 获取类型名称
        /// </summary>
        /// <param name="typeName"></param>
        /// <returns></returns>
        private string getFriendlyTypeName(string typeName)
        {
            var index = typeName.IndexOf('`');
            if (index > 0)
            {
                String name = typeName.Substring(0, index);
                int count = int.Parse(typeName.Substring(index + 1, 1));

                name += "<";
                for (int i = 0; i < count; i++)
                {
                    name = name + "T, ";
                }
                name = name.TrimEnd(',', ' ') + ">";

                return name;
            }

            return typeName;
        }

        private string getFriendlyTypeName(Type activityType)
        {
            string displayName = String.Empty;

            var nameAttri = activityType.GetCustomAttribute<DisplayNameAttribute>(false);
            if (nameAttri != null)
            {
                displayName = nameAttri.DisplayName;
            }

            if (String.IsNullOrWhiteSpace(displayName))
            {
                displayName = getFriendlyTypeName(activityType.Name);
            }

            return displayName;
        }

        private string getFriendlyAssemblyName(string assemblyName)
        {
            string displayName = String.Empty;
            string[] names = assemblyName.Split(new string[] { "." }, StringSplitOptions.RemoveEmptyEntries);
            if (names != null && names.Length > 0)
            {
                displayName = names[names.Length - 1];
            }
            else
            {
                displayName = assemblyName;
            }

            return displayName;
        }

        private bool checkBrowsable(Type type)
        {
            var result = true;
            var browsableAttri = type.GetCustomAttribute<BrowsableAttribute>(false);

            if (browsableAttri != null)
            {
                result = browsableAttri.Browsable;
            }

            return result;
        }
    }
}
